﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;

namespace dasBlog.Storage.SqlServer
{
    public abstract class SqlStorageProviderBase<StgType, SqlType, DCType> : 
        IStorageProvider<StgType>, IInitStorageProvider
        where StgType : class, new()
        where SqlType : class, new()
        where DCType : DataContext, new()
    {
        protected DCType ReadContext
        {
            get
            {
                EnsureInit();
                return _readContext;
            }
        }

        protected DCType _readContext;
        private string connectString = null;
        private bool initialized = false;

        public SqlStorageProviderBase()
        {
            connectString = Properties.Settings.Default.dasBlogStorageSqlConnectionString;
        }

        void IInitStorageProvider.Initialize(string initData)
        {
            connectString = initData;
        }

        void EnsureInit()
        {
            if (!initialized)
            {
                _readContext = CreateDataContext();
                initialized = true;
            }
        }

        private DCType CreateDataContext()
        {
            return Activator.CreateInstance(typeof(DCType), connectString) as DCType;
        }

        public Moniker Store(Moniker contextId, StgType item)
        {
            Moniker result = null;

            using (var writeContext = CreateDataContext())
            {
                if (contextId.ItemId != null)
                {
                    SqlType existingEntry = ReadContext.GetTable<SqlType>().Single(MatchSingle(contextId));
                    if (existingEntry != null)
                    {
                        UpdateSqlTypeFromStgType(item, existingEntry);
                    }
                    else
                    {
                        SqlType newEntry = FromStgType(contextId, item);
                        writeContext.GetTable<SqlType>().Add(newEntry);
                    }
                    writeContext.SubmitChanges();
                    result = contextId;
                }
                else
                {
                    Moniker contextUri = MonikerFromStgType(item);
                    SqlType newEntry = FromStgType(contextId, item);
                    writeContext.GetTable<SqlType>().Add(newEntry);
                    writeContext.SubmitChanges();
                    result = MonikerFromSqlType(newEntry);
                }
                return result;
            }
        }


        public void Delete(Moniker itemId)
        {
            
            using (var writeContext = CreateDataContext())
            {
                writeContext.GetTable<SqlType>().Remove(
                    writeContext.GetTable<SqlType>().Single(MatchSingle(itemId))
                    );
                writeContext.SubmitChanges();
            }
        }



        public StgType Get(Moniker itemId)
        {
            EnsureInit();
            var result = ReadContext.GetTable<SqlType>().Single(MatchSingle(itemId));
            if ( result != null )
            {
                return FromSqlType(result);
            }
            return null;
        }


        public abstract IEnumerable<PropertyAggregate> Aggregate(Moniker contextId, MonikerMatch contextMatch, string propertyName);
        public abstract IEnumerable<StgType> Select(Moniker contextId, MonikerMatch contextMatch, QueryDescription query);
        protected abstract void UpdateSqlTypeFromStgType(StgType item, SqlType existingEntry);
        protected abstract SqlType FromStgType(Moniker contextUri, StgType item);
        protected abstract StgType FromSqlType(SqlType item);
        protected abstract Moniker MonikerFromSqlType(SqlType newEntry);
        protected abstract Moniker MonikerFromStgType(StgType item);
        protected abstract Func<SqlType, bool> MatchSingle(Moniker contextUri);


    }
}
